package game.worlds;

import hx.utils.KeyboardTools;
import game.utils.DtTools;
import game.data.GameOption;
import game.data.FightAnalysisData;
import echo.Line;
import echo.util.Debug;
import echo.math.Vector2;
import echo.Body;
import hx.ui.UIManager;
import hx.geom.Rectangle;
import game.utils.KeybarodTools;
import game.script.AiScript;
import game.data.IRoleData;
import game.data.CDData;
import game.data.BuffData;
import game.data.HurtData;
import game.event.RoleEvent;
import game.script.RoleScript;
import game.utils.ITimelineTools;
import hx.geom.Matrix;
import hx.assets.Atlas;
import hx.geom.Point;
import hx.geom.ColorTransform;
import hx.utils.ColorUtils;
import game.data.HitData;
import echo.Shape;
import hx.events.Keyboard;
import motion.Actuate;
import hx.display.Image;
import game.data.ActionData;
import game.data.FrameData;
import hx.events.Event;
import game.data.RoleData;
import hx.display.MovieClip;
import game.assets.RoleAssets;
import hx.display.Box;

/**
 * 游戏战斗角色
 */
class GameRole extends Box implements IAttackDisplay implements IAnimate {
	/**
	 * 战斗数据统计
	 */
	public var fightAnalysisData:FightAnalysisData = new FightAnalysisData();

	/**
	 * 输入键码，`-1`或者不存在时则为没有按下，否则为按下的时间戳
	 */
	private var __keys:Map<Int, Float> = [];

	/**
	 * AI控制器
	 */
	public var aiScript(get, set):AiScript;

	private var __aiScript:AiScript;

	private function set_aiScript(value:AiScript):AiScript {
		if (__aiScript != null) {
			__aiScript.role = null;
		}
		__aiScript = value;
		if (__aiScript != null) {
			__aiScript.role = this;
		}
		return value;
	}

	private function get_aiScript():AiScript {
		return __aiScript;
	}

	/**
	 * 角色脚本
	 */
	public var script:RoleScript;

	public var nowTime:Float = 0;

	/**
	 * 当前角色被击中的次数
	 */
	public var hitedTimes:Float = 0;

	/**
	 * 累积百分比生命被伤害值
	 */
	public var percentHurtValue:Float = 0;

	/**
	 * 当前角色被击中的时间
	 */
	private var __hitedTime:Float = 0;

	/**
	 * BUFF数据
	 */
	public var buffData:BuffData = new BuffData();

	/**
	 * 技能冷却数据
	 */
	public var cdData:CDData = new CDData();

	public var hitScaleX(get, never):Int;

	private function get_hitScaleX():Int {
		return this.scaleX > 0 ? 1 : -1;
	}

	/**
	 * 角色资源
	 */
	public var assets:RoleAssets;

	/**
	 * 角色原始动作数据
	 */
	public var roleData(get, never):IRoleData;

	private var __roleData:IRoleData;

	private function get_roleData():IRoleData {
		return __roleData;
	}

	/**
	 * 角色动画显示对象
	 */
	public var movieClips:Map<String, MovieClip> = [];

	/**
	 * 当前渲染的动画显示对象
	 */
	private var __movieClip:MovieClip;

	/**
	 * 当前世界
	 */
	public var world:World;

	/**
	 * 角色数据
	 */
	public var data:RoleData;

	/**
	 * 空中可攻击次数
	 */
	public var airAttackTimes:Int = 1;

	/**
	 * 当前角色的输入组合键
	 */
	public var groupKeys:Array<Int> = [];

	/**
	 * 组合键时间
	 */
	private var __groupKeyTime:Float = 0.;

	/**
	 * 已使用的强制技能次数
	 */
	private var __maxForceSkillTimes:Int = 0;

	/**
	 * 当前角色是否停止移动动画，这个用来解决来回切换跑步的时候的频繁站立的问题
	 */
	private var __stopMoveAnimateTime:Float = 0.;

	/**
	 * 队伍值
	 */
	public var troop:Int = 0;

	/**
	 * 攻击的碰撞块预设，如果不存在`hitBody`，则意味着该对象无法被攻击
	 */
	public var hitBody(default, set):Body;

	private function set_hitBody(value:Body):Body {
		if (hitBody != null) {
			hitBody.entity = null;
			if (hitBody.world != null)
				hitBody.world.remove(hitBody);
		}
		this.hitBody = value;
		if (value != null) {
			value.entity = this;
			if (value.world == null && this.world != null) {
				this.world.echoWorld.add(value);
			}
		}
		return body;
	}

	/**
	 * 物理碰撞器
	 */
	public var body(default, set):Body;

	private function set_body(value:Body):Body {
		if (body != null) {
			if (world != null) {
				this.world.roleBoids.remove(body);
			}
			body.entity = null;
			body.on_move = null;
			if (body.world != null)
				body.world.remove(body);
		}
		this.body = value;
		if (value != null) {
			if (world != null) {
				this.world.roleBoids.push(body);
			}
			value.entity = this;
			value.on_move = this.setPoint;
			if (value.world == null && this.world != null) {
				this.world.echoWorld.add(value);
			}
		}
		return body;
	}

	/**
	 * 是否无敌状态
	 */
	public var isInvincible(get, never):Bool;

	/**
	 * 无敌时间
	 */
	public var invincibleTime:Float = 0.;

	/**
	 * 是否霸体状态
	 */
	public var isStoic(get, never):Bool;

	private function get_isStoic():Bool {
		return this.stoicTime > 0.;
	}

	/**
	 * 霸体时间
	 */
	public var stoicTime:Float = 0.;

	/**
	 * 正面格挡时间，当存在该值时，正向攻击的会自动被格挡掉，与防御机制保持一致
	 */
	public var obverseDefanceTime:Float = 0.;

	/**
	 * 自定义数据
	 */
	public var customData:Dynamic = {};

	/**
	 * 霸体显示渲染对象
	 */
	public var stoicDisplay:StoicDisplay;

	private function get_isInvincible():Bool {
		return this.__currentActionName == RoleAction.GET_UP || invincibleTime > 0.;
	}

	/**
	 * 是否处于受伤状态
	 */
	public var isHurt(get, never):Bool;

	private function get_isHurt():Bool {
		return this.__beHitData != null && !this.__beHitData.isDefense;
	}

	/**
	 * 上一个点位置X
	 */
	private var __lastX:Float = 0;

	/**
	 * 上一个点位置Y
	 */
	private var __lastY:Float = 0;

	public function updateLastPoint():Void {
		this.__lastX = this.x;
		this.__lastY = this.y;
	}

	/**
	 * 是否已经被击飞
	 */
	public var isHitFly:Bool = false;

	/**
	 * 原始的角色ID
	 */
	public var roleid(get, never):String;

	private function get_roleid():String {
		return this.assets.id;
	}

	/**
	 * 创建角色
	 * @param world 世界
	 * @param assets 角色资源
	 * @param roleid 角色ID，如果不提供，则使用`assets.id`
	 */
	public function new(world:World, assets:RoleAssets, roleid:String = null) {
		super();
		this.buffData.role = this;
		this.world = world;
		this.assets = assets;
		switchRole(roleid ?? assets.id);
		stoicDisplay = new StoicDisplay();
		this.addChild(stoicDisplay);

		var width = 10;
		var height = 5;
		var tileWidth = width / 2;
		body = new Body({
			material: {
				gravity_scale: 0
			},
			shape: {
				type: POLYGON,
				vertices: [
					new Vector2(-tileWidth, -height),
					new Vector2(tileWidth, -height),
					new Vector2(tileWidth, 0),
					new Vector2(-tileWidth, 0)
				]
			}
		});

		// 默认的碰撞块大小
		var width = 20;
		var height = 70;
		var tileWidth = width / 2;
		this.hitBody = new Body({
			shape: {
				type: POLYGON,
				vertices: [
					new Vector2(-tileWidth, -height),
					new Vector2(tileWidth, -height),
					new Vector2(tileWidth, 0),
					new Vector2(-tileWidth, 0)
				]
			}
		});
	}

	public function setPoint(x:Float, y:Float):Void {
		super.x = x;
		super.y = y;
		if (this.hitBody != null) {
			this.hitBody.x = x;
			this.hitBody.y = y;
			if (!isHurt) {
				var len = Point.distanceByFloat(this.hitBody.last_x, this.hitBody.last_y, x, y);
				this.fightAnalysisData.event(MOVE_DISTANCE, len);
			}
		}
	}

	override function set_x(value:Float):Float {
		if (this.body != null)
			this.body.x = value;
		else
			super.x = value;
		if (this.hitBody != null)
			this.hitBody.x = value;
		return value;
	}

	override function set_y(value:Float):Float {
		if (this.body != null)
			this.body.y = value;
		else
			super.y = value;
		if (this.hitBody != null)
			this.hitBody.y = value;
		return value;
	}

	public function updateAllMovieClipActionData(cleanAll:Bool = false) {
		if (cleanAll) {
			movieClips = [];
		}
		for (key => _ in this.roleData.actions) {
			this.updateMovieClipActionData(key);
		}
	}

	/**
	 * 更新影片剪辑的动作数据
	 * @param key 
	 */
	public function updateMovieClipActionData(key:String):Void {
		var action = this.roleData.actions.get(key);
		if (action == null)
			return;
		var mc = movieClips.exists(key) ? movieClips.get(key) : new MovieClip();
		mc.smoothing = false;
		// 需要清理一下mc中的旧动作配置
		mc.cleanFrames();
		for (frame in action.frames) {
			var args = frame.name.split(":");
			var content:Atlas = null;
			if (this.roleData.atlas == null) {
				content = assets.atlases.get("content");
			} else {
				content = assets.atlases.get(args[0]);
			}
			mc.addFrame(content == null ? null : content.bitmapDatas.get(args[1]), action.fps > 0 ? 1 / action.fps : 1 / 12,
				frame.sound == null ? null : assets.sounds.get(frame.sound), this.roleData.getOffestPoint(args[0]));
		}
		movieClips.set(key, mc);
		mc.scaleX = mc.scaleY = this.roleData.attrData.getBodyScale();
		if (!mc.hasEventListener(Event.COMPLETE))
			mc.addEventListener(Event.COMPLETE, onPlayComplete);
		if (!mc.hasEventListener(Event.CHANGE))
			mc.addEventListener(Event.CHANGE, onPlayChange);
		mc.updateEnabled = false;
		mc.useFrameRect = false;
	}

	/**
	 * 当前正在播放的动作名称
	 */
	private var __currentActionName:String;

	/**
	 * 当前正在使用的技能动作名称
	 */
	private var __currentSkillActionName:String;

	/**
	 * 当前是否正在使用技能
	 */
	public var isSkilling(get, never):Bool;

	private function get_isSkilling():Bool {
		if (isStopAction)
			return false;
		return __currentSkillActionName != null;
	}

	public var isStopAction(get, never):Bool;

	private function get_isStopAction():Bool {
		return __currentSkillActionName == this.__currentStopAction;
	}

	private var __stopEnd:Bool = false;

	/**
	 * 播放动作
	 * @param action 
	 * @param stopEnd 是否在播放结束后，永远停止在最后一帧
	 */
	public function play(action:String, stopEnd:Bool = false):Void {
		if (__currentActionName != action || __movieClip == null) {
			this.__stopEnd = stopEnd;
			__currentActionName = action;
			if (__movieClip != null)
				__movieClip.colorTransform = null;
			this.removeChildren();
			var mc = movieClips.get(action);
			if (mc != null) {
				// 重头播放
				mc.currentFrame = 0;
				this.addChild(mc);
				mc.play(stopEnd ? 1 : -1);
			}
			__movieClip = mc;
			onTransform(0);
			this.__frameDirty = true;
			onFrameChange();
		}
	}

	#if editer
	/**
	 * 播放并停止到某帧，该API仅提供给编辑器使用
	 * @param action 
	 * @param at 
	 */
	public function playAndStop(action:String, at:Int):Void {
		this.play(action);
		if (__movieClip != null) {
			__movieClip.reset();
			for (effectv2 in this.effects) {
				effectv2.clean();
			}
			this.effects = [];
			__dt = 0;
			stoicTime = 0;
			invincibleTime = 0;
			__movieClip.currentFrame = 0;
			__movieClip.enableSound = false;
			__movieClip.play();
			#if editer
			this.x = 0;
			this.y = 0;
			__lastPreviewMoveX = 0;
			__lastPreviewMoveY = 0;
			#end
			__frameDirty = true;
			this.onFrameChange();
			if (at == 0) {
				this.onUpdate(0);
			} else {
				while ((__movieClip.currentFrame < at && __movieClip.currentFrame + 1 < __movieClip.totalFrame)) {
					// 播放到指定帧
					this.onUpdate(GameOption.DT_FPS);
					for (effect in this.effects) {
						effect.onUpdate(GameOption.DT_FPS);
					}
					#if editer
					this.world.onEchoUpdate(GameOption.DT_FPS);
					#end
				}
			}
			#if editer
			this.x -= __lastPreviewMoveX;
			this.y -= __lastPreviewMoveY;
			#end
			__movieClip.stopAt(at);
			__movieClip.enableSound = true;
			// trace("最终坐标", this.x, this.y);
		}
	}
	#end

	private var __frameDirty:Bool = true;

	private function onPlayChange(e:Event):Void {
		// 发生变化时触发，如产生特效处理
		__frameDirty = true;
		this.onFrameChange();
	}

	/**
	 * 当前播放的动作名称
	 */
	public var actionName(get, never):String;

	private function get_actionName():String {
		if (this.currentActionData != null) {
			return this.currentActionData.name;
		}
		return null;
	}

	/**
	 * 动画播放完毕事件处理
	 * @param e 
	 */
	private function onPlayComplete(e:Event):Void {
		// 起身的时候0.5秒无敌时间
		if (this.actionName == RoleAction.GET_UP) {
			this.invincibleTime = 0.5;
		}
		if (this.actionName == RoleAction.HIT) {
			if (this.__beHitData == null) {
				stopSkill();
			}
		} else {
			this.stopSkill();
		}
	}

	/**
	 * 动画变更处理
	 */
	public function onActionChange():Void {
		#if !editer
		if (this.__currentSkillActionName == RoleAction.HIT_MAP
			&& (this.isKeyDown(this.__keyReceiver.LEFT) || this.isKeyDown(this.__keyReceiver.RIGHT))) {
			this.stopSkill();
		}
		if (this.isHurt) {
			// 受伤状态
			if (isHitFly && jumping) {
				if (__jumpForce > 0) {
					this.play(RoleAction.HIT_FLY_UP);
				} else {
					this.play(RoleAction.HIT_FLY_DOWN);
				}
			} else {
				this.play(RoleAction.HIT, true);
			}
		} else if (__currentSkillActionName != null) {
			// 优先播放技能动作
			this.play(__currentSkillActionName);
		} else if (this.jumping) {
			// 跳跃动画
			if (__jumpForce > 0) {
				this.play(RoleAction.JUMP_UP);
			} else {
				this.play(RoleAction.JUMP_DOWN);
			}
		} else if (this.isKeyDown(this.__keyReceiver.DOWN)) {
			// 防御
			if (this.actionName != RoleAction.DEFEND) {
				// 记录一次防御时间
				__defendTime = nowTime;
			}
			this.play(RoleAction.DEFEND);
		} else if (this.isKeyDown(this.__keyReceiver.LEFT) || this.isKeyDown(this.__keyReceiver.RIGHT) || __stopMoveAnimateTime > 0.2) {
			// 移动
			this.play(this.roleData.actions.exists(RoleAction.RUN) ? RoleAction.RUN : RoleAction.WALK);
		} else {
			// 待机
			this.play(RoleAction.IDLE);
		}
		#end
	}

	/**
	 * 记录防御键按下的时间
	 */
	private var __defendTime:Float = 0.;

	/**
	 * 记录攻击键按下的时间
	 */
	private var __attackTime:Float = 0.;

	private function resetGroupKeys():Void {
		groupKeys = [];
	}

	/**
	 * 检测按键组合
	 * @param groupKeys 组合按键，提供[Keyboard.W, Keyboard.A, Keyboard.S, Keyboard.D,Keyboard.J, Keyboard.K, Keyboard.L, Keyboard.U, Keyboard.I, Keyboard.O, Keyboard.P]等基础键值码
	 */
	public function testGroupKey(groupKeys:Array<Int>):Bool {
		return KeybarodTools.testGroupKey(this.groupKeys, groupKeys);
	}

	/**
	 * 输入键码
	 * @param key 
	 */
	public function onKeyDown(key:Int):Void {
		if (!KeybarodTools.enable || this.world.paused)
			return;

		// 防止长按JUMP造成不良跳跃
		if (key == this.keyReceiver.JUMP && __keys.exists(this.keyReceiver.JUMP))
			return;

		var existKey = __keys.exists(key);
		__keys.set(key, this.world.worldRunTime);

		// 超过组合键有效时间，则清空组合键
		if (this.world.worldRunTime - __groupKeyTime > 0.2) {
			resetGroupKeys();
		}
		__groupKeyTime = this.world.worldRunTime;
		// 追加组合键，这里读取的是原始key，即ASWD JKLUIOP
		if (!existKey)
			groupKeys.push(__keyReceiver.getOrginKey(key));
		if (__keyReceiver.hasAttackKey(key)) {
			if (this.isHurt)
				return;

			if (this.actionName == RoleAction.GET_UP) {
				return;
			}

			// 使用了攻击性、技能键、测试组合键
			__attackTime = this.world.worldRunTime;

			if (__currentBeStopAction != null) {
				this.playSkill(__currentBeStopAction, true, true);
				this.goToFrame(__currentBeStopActionFrame);
				__currentBeStopAction = null;
			} else {
				// 自动补键位逻辑实现
				var groupKeys = groupKeys.copy();
				if (groupKeys.length == 1) {
					if (this.isKeyDown(__keyReceiver.UP)) {
						groupKeys.insert(0, __keyReceiver.getOrginKey(__keyReceiver.UP));
					} else if (this.isKeyDown(__keyReceiver.DOWN)) {
						groupKeys.insert(0, __keyReceiver.getOrginKey(__keyReceiver.DOWN));
					}
				}
				for (actionData in this.roleData.groupKeyActions) {
					if (actionData.testGroupKey(groupKeys, jumping)) {
						if (isSkilling) {
							if (actionData.name == this.__currentSkillActionName) {
								break;
							}
							// 普通攻击、空中攻击不允许强制
							if (actionData.testGroupKey([Keyboard.J], true) || actionData.testGroupKey([Keyboard.J], false)) {
								break;
							}
							// 要判断当前技能是否可以为二次强制
							if (actionData.diabledForceFirst) {
								break;
							}
							// 不允许强制释放时
							if (this.currentActionData.diabledForce) {
								break;
							}
							if (__maxForceSkillTimes < this.data.maxForceSkillTimes) {
								__maxForceSkillTimes++;
								this.fightAnalysisData.event(TOTAL_SHADOW_TIMES);
							} else {
								break;
							}
						}
						this.playSkill(actionData.name);
						break;
					}
				}
			}
			// 这里需要清空组合键
			resetGroupKeys();
		} else if (key == __keyReceiver.JUMP) {
			if (__jumpTimes < data.maxJumpTimes) {
				if (!isHurt) {
					if (__currentActionName == "普通攻击" || __currentActionName == "空中攻击" || isStopAction || currentActionData.canJumpStop) {
						stopSkill();
					}
					if (!isSkilling) {
						if (isKeyDown(__keyReceiver.DOWN)
							&& !jumping
							&& __hitMapDisplay != null
							&& __hitMapDisplay.filter(a -> a.name == "unjump").length == 0) {
							// 跳跃到台阶下面
							this.__igonreHitMapDisplay = this.__hitMapDisplay.copy();
							this.jump(0);
						} else {
							__jumpTimes++;
							this.jump();
							this.airAttackTimes = this.data.maxAirAttackTimes;

							var effect = new GameEffect(this, this.body.velocity.x == 0 ? "jump" : "jump2");
							this.world.addDisplay(effect);
							effect.x = this.x;
							effect.y = this.y;
							effect.blendMode = ADD;
							effect.scaleX = 0.4 * this.scaleX;
							effect.scaleY = 0.4;

							// 角度方向
							// var angleX = this.body.velocity.x;
							// var angleY = this.data.jump / 0.016;
							// var rotation = Point.rotationByFloat(0, 0, -angleX, angleY);
							// effect.rotation = rotation - 90;
						}
						this.world.assets.playSound("jump");
					}
				} else {
					// 快速起身，控制在指定的掉落速度中可以允许快速起身
					if (isHitFly && __jumpForce < 0 && __jumpForce > -10 && this.cardFrameTime <= 0) {
						this.stiffenTime = 0;
						__quickJump = true;
						__jumpTimes = data.maxJumpTimes;
						isHitFly = false;
						this.jump(0.75);
						this.airAttackTimes = this.data.maxAirAttackTimes;
						this.world.assets.playSound("jump");
						// 赋予0.3秒霸体
						this.stoicTime = 0.1;
					}
				}
			}
		} else if (key == __keyReceiver.FAST_MOVE) {
			this.playSkill(RoleAction.FAST_MOVE);
		}
	}

	/**
	 * 已跳跃次数，如果设置大于最大跳跃次数，则无法继续跳跃
	 */
	public var jumpedTimes(get, set):Int;

	private function get_jumpedTimes():Int {
		return __jumpTimes;
	}

	private function set_jumpedTimes(value:Int):Int {
		__jumpTimes = value;
		return value;
	}

	/**
	 * 释放所有按键
	 */
	public function releaseAllKeys():Void {
		for (index => value in __keys) {
			if (value != -1) {
				this.onKeyUp(index);
			}
		}
	}

	/**
	 * 当前站着的地图块对象
	 */
	private var __hitMapDisplay:Array<MapDisplay> = [];

	/**
	 * 忽略碰撞的地图块对象
	 */
	private var __igonreHitMapDisplay:Array<MapDisplay> = [];

	/**
	 * 跳跃测试次数
	 */
	private var __jumpTestTimes = 0;

	private var __unjumpTime:Float = 0;

	/**
	 * 检测是否碰撞地图
	 * @return Bool
	 */
	private function onHitMap(dt:Float):Bool {
		var isJump = true;

		// 射线检测
		var line = Line.get(this.body.x, this.body.y - 10, this.body.x, this.body.y + 15);
		var testList = this.world.mapBoids;
		var ret = line.linecast(testList, this.world.echoWorld);
		line.start.x = this.body.x - 5;
		line.end.x = this.body.x - 5;
		var left = line.linecast(testList, this.world.echoWorld);
		line.start.x = this.body.x + 5;
		line.end.x = this.body.x + 5;
		var right = line.linecast(testList, this.world.echoWorld);
		var isCheckCenter = false;
		if (ret == null) {
			ret = left;
		} else {
			isCheckCenter = true;
		}
		if (ret == null) {
			ret = right;
		}
		if (ret == null && __hitMapDisplay.length > 0) {
			__unjumpTime += dt;
			if (__unjumpTime >= 0.05) {
				__hitMapDisplay = [];
			}
		} else if (__hitMapDisplay.length > 0) {
			__unjumpTime = 0;
			// 检测是否为下坡
			if (ret != null && isCheckCenter && !jumping) {
				if (currentFrameData == null || currentFrameData.moveY >= 0) {
					// 是否碰撞块脱离，如果是，则判断是否碰撞
					var leftY = left != null ? left.closest.hit.y : 100000;
					var rightY = right != null ? right.closest.hit.y : 100000;
					var centerY = ret.closest.hit.y;
					this.body.x = ret.closest.hit.x;
					this.body.y = Math.min(centerY, Math.min(leftY, rightY));
				}
			}
		}

		if (__hitMapDisplay.length > 0) {
			isJump = false;
		}

		if (isJump) {
			if (!jumping) {
				jump(0);
			}
		} else if (jumping && this.__jumpForce <= 0) {
			onJumped();
		}
		return !isJump;
	}

	/**
	 * 停止键码
	 * @param key 
	 */
	public function onKeyUp(key:Int):Void {
		__keys.remove(key);
	}

	/**
	 * 是否按下了某个按键
	 * @param key 
	 * @return Bool
	 */
	public function isKeyDown(key:Int):Bool {
		return __keys.exists(key);
	}

	/**
	 * 获得按键按下的时间，如果没有按下该按键，则返回`-1`
	 * @param key 
	 * @return Float
	 */
	public function getKeyDownTime(key:Int):Float {
		if (__keys.exists(key))
			return __keys.get(key);
		return -1;
	}

	/**
	 * 获得当前帧
	 */
	public var currentFrame(get, never):Int;

	private function get_currentFrame():Int {
		return __movieClip != null ? __movieClip.currentFrame : 0;
	}

	/**
	 * 读取当前位移帧数据
	 */
	public var currentFrameData(get, never):FrameData;

	private function get_currentFrameData():FrameData {
		return getFrameDataAt(this.currentFrame);
	}

	/**
	 * 根据帧位置获得当前帧数据
	 * @param frame 
	 * @return FrameData
	 */
	public function getFrameDataAt(frame:Int):FrameData {
		return this.roleData.actions[__currentActionName]?.frames[frame];
	}

	/**
	 * 当前动作数据
	 */
	public var currentActionData(get, never):ActionData;

	private function get_currentActionData():ActionData {
		return this.roleData.actions[__currentActionName];
	}

	#if editer
	var __lastPreviewMoveX:Float = 0;
	var __lastPreviewMoveY:Float = 0;
	#end

	/**
	 * 计算缩放、旋转、透明度等实现
	 * @param dt 
	 */
	public function onTransform(dt:Float):Void {
		if (this.__movieClip == null)
			return;
		var frameData = this.currentFrameData;
		var data = this.__movieClip.currentCustomData;
		if (data != null)
			ITimelineTools.updateTransform(this.__movieClip, frameData, this.currentActionData, data.x, data.y, this.roleData.attrData.getBodyScale(), dt);
		else {
			ITimelineTools.updateTransform(this.__movieClip, frameData, this.currentActionData, 0, 0, this.roleData.attrData.getBodyScale(), dt);
		}
	}

	/**
	 * 成功攻击敌人时触发
	 * @param enemy 
	 */
	public function onAttackEnemy(enemy:IAttackDisplay):Void {}

	private var __readyMovePoint:Point = new Point();

	public function move(x:Float, y:Float):Void {
		__readyMovePoint.x += x;
		__readyMovePoint.y += y;
	}

	/**
	 * 设置僵直时间
	 */
	public var stiffenTime(get, set):Float;

	private function get_stiffenTime():Float {
		return __beHitData != null ? __beHitData.stiffenTime : 0;
	}

	private function set_stiffenTime(value:Float):Float {
		if (__beHitData == null) {
			__beHitData = new HitData();
		}
		__beHitData.stiffenTime = value;
		return value;
	}

	/**
	 * 移动逻辑
	 */
	public function onMove(dt:Float):Void {
		if (cardFrameTime > 0)
			return;

		if (__stopMoveAnimateTime > 0) {
			__stopMoveAnimateTime -= dt;
		}
		var skilling = this.isSkilling;
		var dtScale = DtTools.mathTimeScale(dt);

		this.body.velocity.x += __readyMovePoint.x * dtScale;
		this.body.velocity.y += __readyMovePoint.y * dtScale;

		var airScale = (skilling && !this.currentActionData.allowAirMove) ? this.currentActionData.airGravity : 1;
		// 如果是空中技能，就不应该收到重力影响，除非是选择了空中移动
		if (!this.currentActionData.allowAirMove && this.currentActionData.type == AIR_SKILL) {
			airScale = 0;
		}
		if (currentFrameData != null && this.currentFrameData.moveY != 0) {
			airScale = 0;
		}
		// 受伤状态处理位移
		if (__beHitData != null) {
			if (!isHitFly || !jumping)
				__beHitData.stiffenTime -= dt;
			// 非击飞状态下，需要有减速效果
			if (!this.jumping)
				__beHitData.hitMoveX += (0 - __beHitData.hitMoveX) * (__beHitData.isDefense ? 0.1 : 0.03) * dtScale;
			this.body.velocity.x += __beHitData.hitMoveX * dtScale;
			if (__beHitData.stiffenTime <= 0) {
				__beHitData = null;
			}
		}
		if (!this.isHurt) {
			if (#if editer true #else this.__currentSkillActionName != null #end) {
				// 技能需要读取moveX/moveY进行位移
				var frameData = this.currentFrameData;
				if (frameData != null) {
					ITimelineTools.updateMove(this, frameData, this.currentActionData, this.roleData.attrData.getBodyScale(), dt);
				}
			}
			#if !editer
			// 技能释放时允许移动
			if (!skilling || this.currentActionData.allowAirMove) {
				if (this.isKeyDown(__keyReceiver.LEFT)) {
					if (!skilling)
						this.scaleX = -1;
					if (!isDefense)
						this.body.velocity.x -= this.data.speed * dtScale * this.roleData.attrData.getBodyScale();
					__stopMoveAnimateTime = 0.25;
				} else if (this.isKeyDown(__keyReceiver.RIGHT)) {
					if (!skilling)
						this.scaleX = 1;
					if (!isDefense)
						this.body.velocity.x += this.data.speed * dtScale * this.roleData.attrData.getBodyScale();
					__stopMoveAnimateTime = 0.25;
				}
			}
			#end
		}

		if (__jumping && airScale != 0) {
			// 跳跃系数调整
			this.__jumpForce -= GameOption.JUMP_RATIO * dtScale * airScale;
			// Math.min(Math.abs(1 - this.__jumpForce * 0.5), 1)
			// this.y -= this.__jumpForce * dtScale;
			if (this.__jumpForce > 0 && this.__jumpForce < 2) {
				this.body.velocity.y -= this.__jumpForce * 0.2 * dtScale * this.roleData.attrData.getBodyScale();
			} else {
				this.body.velocity.y -= this.__jumpForce * dtScale * this.roleData.attrData.getBodyScale();
			}
		} else {
			__jumpForce = 0;
		}
		#if !editer
		// 边界限制
		if (this.body.x < 30) {
			this.body.x = 30;
		} else if (this.x > this.world.mapWidth - 30) {
			this.body.x = this.world.mapWidth - 30;
		}
		#end
	}

	/**
	 * 角色攻击碰撞生效帧
	 */
	private var __hitFrameData:FrameData;

	/**
	 * 角色攻击碰撞块有效时间
	 */
	private var __hitCollisionTime:Float = 0;

	/**
	 * 当前被停顿的动作
	 */
	public var __currentBeStopAction:String;

	/**
	 * 当前正在释放的停顿动作
	 */
	public var __currentStopAction:String;

	public var __currentBeStopActionFrame:Int = 0;

	/**
	 * 当前已释放的技能特效
	 */
	public var effects:Array<GameEffect> = [];

	public var isPlaying(get, never):Bool;

	private function get_isPlaying():Bool {
		return __movieClip != null && __movieClip.playing;
	}

	/**
	 * 判断检测碰撞条件
	 * @param body 
	 * @return Bool
	 */
	public function condition(body:Body):Bool {
		if (__igonreHitMapDisplay.indexOf(cast body.entity) != -1) {
			return false;
		}
		return true;
	}

	/**
	 * 碰撞触发
	 * @param body 
	 */
	public function enter(body:Body):Void {
		if (body.entity != null && body.entity is MapDisplay)
			__hitMapDisplay.push(cast body.entity);
	}

	private function onFrameChange() {
		if (!__frameDirty)
			return;
		__frameDirty = false;
		var i = effects.length;
		while (i-- > 0) {
			var eff = effects[i];
			if (eff.parent == null) {
				effects.splice(i, 1);
			}
		}
		var currentFrameData = this.currentFrameData;
		if (currentFrameData != null) {
			// 特效解析处理
			ITimelineTools.parserGameEffect(currentFrameData, this);
			// 停顿帧检测
			if (#if editer false #else currentFrameData.isStop #end) {
				if (this.world.worldRunTime - __attackTime > 0.2) {
					// 如果存在停顿动作，则进入停顿动作
					if (currentFrameData.stopAction != null) {
						__currentBeStopAction = this.currentActionData.name;
						__currentBeStopActionFrame = currentFrameData.frame + 1;
						this.playSkill(currentFrameData.stopAction, false);
						this.__currentStopAction = currentFrameData.stopAction;
					} else {
						stopSkill();
					}
				} else if (this.isKeyDown(__keyReceiver.LEFT) || this.isKeyDown(__keyReceiver.RIGHT)) {
					// 支持转向
					this.scaleX = this.isKeyDown(__keyReceiver.LEFT) ? -1 : 1;
				}
			}
			// 碰撞块检测
			if (currentFrameData.collision != null && currentFrameData.collision.shapes.length > 0) {
				if (currentFrameData.shareCollision) {
					if (__hitFrameData != null)
						__hitFrameData.collision = currentFrameData.collision;
				} else {
					__hitFrameData = currentFrameData.copy();
					__hitCollisionTime = currentFrameData.collisionLiveTime;
					// 更新攻击块创建点
					__hitFrameData.hitData.liveTime = __hitFrameData.collisionLiveTime;
					__hitFrameData.hitData.updateCreatePoint(this.x, this.y, this.scaleX > 0 ? 1 : -1);
					__hitFrameData.hitData.hitedTime = 0;
				}
			} else if (__hitFrameData != null && (__hitFrameData.frame > this.currentFrame)) {
				__hitFrameData = null;
			}
			currentFrameData.shake(this.world);
			if (currentFrameData.invincibleTime > this.invincibleTime) {
				this.invincibleTime = currentFrameData.invincibleTime;
			}
			if (currentFrameData.stoicTime > this.stoicTime) {
				this.stoicTime = currentFrameData.stoicTime;
			}
		}
		if (__maxForceSkillTimes > 0)
			this.createShadow();
		if (this.hasEventListener(RoleEvent.FRAME_CHANGE)) {
			var event = new RoleEvent(RoleEvent.FRAME_CHANGE);
			if (this.currentFrameData != null && this.currentFrameData.eventTag != "") {
				event.data = this.currentFrameData.eventTag;
			}
			this.dispatchEvent(event);
		}
		if (this.hasEventListener(RoleEvent.EVENT)) {
			if (this.currentFrameData != null && this.currentFrameData.eventTag != "") {
				var event = new RoleEvent(RoleEvent.EVENT);
				event.data = this.currentFrameData.eventTag;
				this.dispatchEvent(event);
			}
		}
	}

	override function dispatchEvent(event:Event) {
		if (event is RoleEvent) {
			var roleEvent:RoleEvent = cast event;
			roleEvent.action = this.currentActionData.name;
			roleEvent.frame = this.currentFrame;
		}
		super.dispatchEvent(event);
	}

	override function addEventListener<T>(type:String, listener:T->Void) {
		super.addEventListener(type, listener);
	}

	/**
	 * 防御状态
	 */
	public var isDefense(get, never):Bool;

	private function get_isDefense():Bool {
		return this.__currentActionName == RoleAction.DEFEND;
	}

	/**
	 * 被击中的效果
	 */
	private var __beHitData:HitData;

	/**
	 * 击中敌人的时间
	 */
	private var __hitedRoleTime:Float = 0;

	/**
	 * 设置卡帧时间
	 * @param time 
	 */
	public function setStopFrameTime(time:Float):Void {
		if (this.stoicTime > 0 || this.obverseDefanceTime > 0)
			time *= 0.5;
		if (time > this.cardFrameTime) {
			this.cardFrameTime = time;
		}
	}

	/**
	 * 应用击中效果
	 * @param attackDisplay 攻击者
	 * @param hitData 攻击数据
	 * @param hitScaleX 攻击方向
	 */
	public function applyHitData(attackDisplay:IAttackDisplay, hitData:HitData, hitScaleX:Int):Void {
		var role = attackDisplay.getRole();

		var currentDefenseState = this.isDefense && !hitData.isDestroyDefense;

		// 造成伤害
		var hurtData = new HurtData();
		hurtData.hitData = hitData;
		hurtData.attackType = hitData.attackType;
		hurtData.value = role.data.mathAttack(hitData);
		if (currentDefenseState) {
			hurtData.value = Math.round(hurtData.value * 0.3);
		}
		hurtData.attackDisplay = attackDisplay;
		hurtData.role = this;
		hurtData.event = hitData.eventTag;
		hurtData.value = this.data.mathDefense(hurtData);
		hurtData.hitEffectId = hitData.hitEffectId;
		// 如果没有设置击中特效，则使用全局的
		if (hurtData.hitEffectId == null) {
			hurtData.hitEffectId = role.data.hitEffectId;
		}
		@:privateAccess hurtData.__shapes = attackDisplay.currentHitColliderFrameData.collision;
		@:privateAccess hurtData.__x = hitData.createX;
		@:privateAccess hurtData.__y = hitData.createY;
		@:privateAccess hurtData.__scaleX = attackDisplay.scaleX;

		if (role.hasEventListener(RoleEvent.ATTACK_START)) {
			var event = new RoleEvent(RoleEvent.ATTACK_START);
			event.hurtData = hurtData;
			role.dispatchEvent(event);
			if (event.cannel)
				return;
		}

		if (attackDisplay != role && attackDisplay.hasEventListener(RoleEvent.ATTACK_START)) {
			var event = new RoleEvent(RoleEvent.ATTACK_START);
			event.hurtData = hurtData;
			attackDisplay.dispatchEvent(event);
			if (event.cannel)
				return;
		}

		if (this.hasEventListener(RoleEvent.HURT_START)) {
			var event = new RoleEvent(RoleEvent.HURT_START);
			event.hurtData = hurtData;
			this.dispatchEvent(event);
			if (event.cannel)
				return;
		}

		if (hitData.stiffenTime != 0 && !isStoic) {
			__beHitData = hitData.clone();
			if (__beHitData.stiffenTime < 0) {
				__beHitData.stiffenTime = 0.65;
			}
			// 避免无限平A
			var rate = (0.2 + Math.min(0.8, 0.8 * (1 - Math.min(24, hitedTimes) / 24)));
			__beHitData.stiffenTime *= rate * __beHitData.stiffenTime;
			__beHitData.hitMoveX *= role.roleData.attrData.getBodyScale() * hitScaleX;
			__beHitData.hitMoveY *= role.roleData.attrData.getBodyScale();
			// 需要主动断开技能
			if (this.isSkilling)
				this.stopSkill();
		}

		role.__hitedRoleTime = this.world.worldRunTime;

		// 自动防御逻辑
		if (obverseDefanceTime > 0) {
			currentDefenseState = true;
		}

		// 背击判定：先判断碰撞块的产生点，判断方向
		var len = hitData.createX - this.x;
		var isLeft = hitData.createDirection == 1;
		if (hitData.createDirection == this.scaleX) {
			isLeft = len < 0;
		}

		if (((isLeft && this.scaleX > 0) || (!isLeft && this.scaleX < 0))) {
			// 背击
			var effect = new GameEffect(this, "backhit");
			this.world.addDisplay(effect);
			effect.x = this.x;
			effect.y = this.y - this.height / 2;
			effect.blendMode = ADD;
			effect.scaleX = 0.5 * this.scaleX;
			effect.scaleY = 0.5;
			currentDefenseState = false;
			obverseDefanceTime = 0;
		}

		// 如果气力值为0，也无法防御
		if (this.data.effort < 5) {
			currentDefenseState = false;
		}

		if (currentDefenseState) {
			// 防御成功
			if (this.data.effort > 5)
				this.data.effort -= 5;
			if (__beHitData != null)
				__beHitData.isDefense = true;
			var effect = new GameEffect(this, "defense");
			this.world.addDisplay(effect);
			effect.x = this.x;
			effect.y = this.y - this.height / 2;
			effect.blendMode = ADD;
			effect.scaleX = this.scaleX;
			if (nowTime - __defendTime < 0.5) {
				this.obverseDefanceTime = 0.2;
				__defendTime = 0.;
				// 这里是绝对防御
				var effect = new GameEffect(this, "defense2");
				this.world.addDisplay(effect);
				effect.x = this.x;
				effect.y = this.y - this.height / 2;
				effect.blendMode = ADD;
				effect.scaleX = this.scaleX;
				this.fightAnalysisData.event(PERFECT_DEFEND_SUCCESS_TIMES);
			}
			this.fightAnalysisData.event(TOTAL_DEFEND_SUCCESS_TIMES);
		} else {
			if (this.data.effort < this.data.maxEffort)
				this.data.effort++;
			hitedTimes++;
			__hitedTime = this.nowTime;
			if (this.actionName == RoleAction.HIT) {
				this.goToFrame(0);
			}
		}

		// 攻击成功事件
		if (role.hasEventListener(RoleEvent.ATTACKED)) {
			var event = new RoleEvent(RoleEvent.ATTACKED);
			event.hurtData = hurtData;
			role.dispatchEvent(event);
			if (event.cannel)
				return;
		}

		if (attackDisplay != role && attackDisplay.hasEventListener(RoleEvent.ATTACKED)) {
			var event = new RoleEvent(RoleEvent.ATTACKED);
			event.hurtData = hurtData;
			role.dispatchEvent(event);
			if (event.cannel)
				return;
			attackDisplay.dispatchEvent(event);
		}

		role.data.addMp(10);
		role.data.hitCounts++;
		role.data.hitDamage += hurtData.value;
		role.fightAnalysisData.event(TOTAL_ATTACK_TIMES);
		role.fightAnalysisData.max(MAX_ATTACK_TIMES, role.data.hitCounts);
		role.fightAnalysisData.max(MAX_ATTACK_DAMAGE, role.data.hitDamage);
		role.fightAnalysisData.event(TOTAL_ATTACK_DAMAGE, hurtData.value);
		if (this.__quickJump) {
			this.__quickJump = false;
			role.fightAnalysisData.event(INTERRUPT_ENEMY_AIR_UP_TIMES);
		}
		this.hurt(attackDisplay, hurtData);
		this.percentHurtValue += hurtData.value / role.data.maxHp;

		// 卡帧
		setStopFrameTime(hitData.stopFrameTimeEnemy);
		var selfCardTime = hitData.stopFrameTimeSelf < 0 ? hitData.stopFrameTimeEnemy : hitData.stopFrameTimeSelf;
		if (hitData.applyRoleStopFrame) {
			role.setStopFrameTime(selfCardTime);
			for (effect in role.effects) {
				effect.setStopFrameTime(selfCardTime);
			}
		}
		attackDisplay.setStopFrameTime(selfCardTime);

		// var shake = hitData.stopFrameTimeEnemy > 0 ? (hitData.shakeIntensity == 0 ? 30 : hitData.shakeIntensity) : 0;
		// var time = hitData.shakeDuration > 0 ? hitData.shakeDuration : hitData.stopFrameTimeEnemy;
		if (hitData.shakeIntensity > 0 && hitData.shakeDuration > 0) {
			this.world.camera.shakeManager.addShake(hitData.shakeIntensity, hitData.shakeDuration, hitData.shakeFrequency);
		}

		var soundName:String = null;

		// 是否击飞
		if (hitData.isBlow) {
			this.isHitFly = true;

			var effectHitId = hitData.hitBlowEffectId;
			if (effectHitId == null || effectHitId == "") {
				effectHitId = role.data.hitBlowEffectId;
				if (effectHitId == null || effectHitId == "")
					effectHitId = "boom_hit1";
			}

			var effect = new GameEffect(role, effectHitId);
			this.world.addDisplay(effect);
			effect.x = this.x;
			effect.y = this.y - this.height / 2;
			effect.blendMode = ADD;
			effect.scaleX = effect.scaleY = effectHitId == "boom_hit1" ? 0.5 : 1;
			soundName = this.roleData.attrData.hitSound2;
		} else {
			soundName = this.roleData.attrData.hitSound;
		}

		if (hitData.sound != null) {
			soundName = hitData.sound;
		}

		if (currentDefenseState) {
			// 防御成功，应该变更为防御音效
			soundName = "defense";
		}

		if (hitData.hitMoveX != 0 && !isStoic && !currentDefenseState) {
			this.scaleX = -hitData.createDirection;
		}

		if (!currentDefenseState && !isStoic) {
			if (hitData.hitMoveY != 0) {
				if (jumping && hitData.hitMoveY > 0) {
					this.isHitFly = true;
				}
				this.jumpByForce(mathHitMoveY(hitData.hitMoveY));
			} else if (hitData.stiffenTime != 0 && this.jumping && __jumpForce < 0) {
				this.jumpByForce(mathHitMoveY(2.5));
			}
			Actuate.update(showColor, 0.5, [hitData.hitColor, 1], [hitData.hitColor, 0]);
		}

		// 击中特效产生
		var effect = new GameEffect(role, (hurtData.hitEffectId != "" && hurtData.hitEffectId != null) ? hurtData.hitEffectId : "hit1");
		this.world.displayBox.addChild(effect);
		effect.rotation = Std.random(360);
		effect.x = this.x;
		effect.y = this.y - Std.random(60) - 10;
		effect.blendMode = SCREEN;
		effect.scaleX = effect.scaleY = 0.5;

		if (soundName != null && soundName != "") {
			var sound = this.assets.getSound(soundName);
			if (sound == null) {
				sound = this.world.assets.getSound(soundName);
			}
			if (sound != null)
				sound.root.play();

			attackDisplay.onAttackEnemy(this);
		}
	}

	/**
	 * 当前是否包含了某个按键的技能
	 * @return Bool
	 */
	public function checkSkillKey(key:Int):Bool {
		var action = this.currentActionData;
		if (action != null && action.groupKeys != null) {
			return action.groupKeys.indexOf(key) != -1;
		}
		return false;
	}

	/**
	 * 12刀系统（击飞保护逻辑）
	 * @param v 
	 * @return Float
	 */
	private function mathHitMoveY(v:Float):Float {
		// 必杀忽略必杀
		var percentHurtValue = this.percentHurtValue * 100;
		if (v == 0 || percentHurtValue < 25 || checkSkillKey(Keyboard.O)) {
			return v;
		} else if (percentHurtValue < 40) {
			return v * (1 - ((percentHurtValue - 25) / 15));
		} else {
			return v * (percentHurtValue - 40) / -12;
		}
	}

	/**
	 * 展示颜色
	 * @param color 
	 * @param a 
	 */
	public function showColor(color:UInt, a:Float):Void {
		var color = ColorUtils.toShaderColor(color);
		var outA = 1 - a;
		this.__movieClip.colorTransform = new ColorTransform(color.r * outA, color.g * outA, color.b * outA, 1, 255 * color.r * a, 255 * color.g * a,
			255 * color.b * a, 0);
	}

	/**
	 * 卡帧时间
	 */
	public var cardFrameTime:Float = 0;

	private var __dt:Float = 0;

	override function onUpdate(dt:Float) {
		super.onUpdate(dt);
		if (__movieClip == null)
			return;

		this.fightAnalysisData.event(RUN_TIME, dt);
		if (this.isSkilling) {
			this.fightAnalysisData.event(ATTACK_TIME, dt);
		}

		this.body.velocity.set(0, 0);

		if (aiScript != null)
			aiScript.update(dt);

		if (this.hitedTimes > 0 && this.nowTime - __hitedTime > 3 && !this.isHurt) {
			this.hitedTimes = 0;
		}

		if (percentHurtValue > 0 && !this.isHurt) {
			percentHurtValue -= 0.0025 * dt / GameOption.DT_FPS;
		}

		__readyMovePoint.x = __readyMovePoint.y = 0;
		if (this.hasEventListener(RoleEvent.FRAME_ENTER))
			this.dispatchEvent(new RoleEvent(RoleEvent.FRAME_ENTER));
		if (__dt == 0 && this.currentFrameData != null) {
			if (__movieClip.currentFrame == 0 && @:privateAccess __movieClip.__time == 0) {
				// 初始位移值
				this.body.velocity.x += @:privateAccess this.currentFrameData._originMoveX;
				this.body.velocity.y += @:privateAccess this.currentFrameData._originMoveY;
			}
		}
		if (invincibleTime > 0)
			invincibleTime -= dt;
		if (stoicTime > 0)
			stoicTime -= dt;
		if (obverseDefanceTime > 0)
			obverseDefanceTime -= dt;
		__dt += dt;
		this.advance(dt);
		this.onMove(dt);
		// 碰撞持续时间判断
		if (__hitFrameData != null && __hitFrameData.hitData.liveTime > 0) {
			__hitFrameData.hitData.liveTime -= dt;
			if (__hitFrameData.hitData.liveTime <= 0) {
				__hitFrameData = null;
			}
		}
		@:privateAccess this.buffData.update(dt);
		@:privateAccess this.cdData.update(dt);
		#if !editer
		if (this.data.hp == 0) {
			if (this.actionName != RoleAction.GET_UP && !this.jumping) {
				this.playSkill(RoleAction.GET_UP);
			}
			this.goToFrame(0);
		}
		#end
		if (stoicTime > 0 || obverseDefanceTime > 0) {
			this.addChildAt(stoicDisplay, 0);
			stoicDisplay.data = __movieClip.data;
			stoicDisplay.x = __movieClip.x;
			stoicDisplay.y = __movieClip.y;
			stoicDisplay.scaleX = __movieClip.scaleX;
			stoicDisplay.scaleY = __movieClip.scaleY;
			stoicDisplay.color = obverseDefanceTime > stoicTime ? 0x00ff00 : 0xffff00;
		} else if (stoicDisplay.parent != null) {
			stoicDisplay.remove();
		}
		if (this.hasEventListener(RoleEvent.FRAME_EXIT))
			this.dispatchEvent(new RoleEvent(RoleEvent.FRAME_EXIT));

		this.body.velocity.x /= dt;
		this.body.velocity.y /= dt;
	}

	private var __effortDtTime:Float = 0;

	private function advance(dt:Float) {
		if (currentActionData == null) {
			return;
		}

		__effortDtTime += dt;
		if (__effortDtTime >= 0.5) {
			__effortDtTime -= 0.5;
			if (this.data.maxEffort > this.data.effort)
				this.data.effort++;
		}

		// 清空被击数
		if (this.data.hitCounts > 0 && this.world.worldRunTime - __hitedRoleTime > 1.5) {
			this.data.hitCounts = 0;
			this.data.hitDamage = 0;
		}

		if (cardFrameTime <= 0) {
			nowTime += dt;
			if (__movieClip != null) {
				__movieClip.onUpdate(dt);
				this.onTransform(dt);
			}
		} else {
			cardFrameTime -= dt;
		}
		this.onActionChange();
		// if (currentActionData.eventTag != null) {
		// 	var event = this.roleData.eventData.actions.get(currentActionData.eventTag);
		// 	if (event != null) {
		// 		event.execute(this);
		// 	}
		// }
		// this.collider.updatePoint(this.x, this.y);
		if (__hitCollisionTime > 0) {
			__hitCollisionTime -= dt;
		}

		this.onFrameChange();
	}

	/**
	 * 键控接收器
	 */
	public var keyReceiver(get, never):Key;

	private function get_keyReceiver():Key {
		return __keyReceiver;
	}

	/**
	 * 按键接收器
	 */
	private var __keyReceiver:Key = new Key();

	/**
	 * 注册键控接收器
	 */
	public function registerKeyReceiver(key:Key):Void {
		this.__keyReceiver = key;
		key.role = this;
	}

	/**
	 * 通过按键进行释放技能
	 * @param skill 
	 */
	public function playSkillFromKey(skill:String):Void {
		var action = this.roleData.actions.get(skill);
		if (action != null && action.groupKeys.length > 0) {
			this.releaseAllKeys();
			for (key in action.groupKeys) {
				this.onKeyDown(keyReceiver.getFromKey(key));
			}
		}
	}

	/**
	 * 播放技能
	 * @param skill 
	 */
	public function playSkill(skill:String, enableScaleX:Bool = true, igroneCD:Bool = false):Void {
		if (skill == RoleAction.JUMP_ATTACK) {
			if (airAttackTimes <= 0) {
				return;
			}
			airAttackTimes--;
		}
		if (!igroneCD && this.cdData.isCDing(skill)) {
			return;
		}
		if (this.hasEventListener(RoleEvent.SKILL_START)) {
			var event = new RoleEvent(RoleEvent.SKILL_START);
			event.data = skill;
			this.dispatchEvent(event);
			if (event.cannel) {
				return;
			}
		}
		// MP值检测
		var readyReleaseSkillData = this.roleData.actions.get(skill);
		if (readyReleaseSkillData.mpConsume * 100 > this.data.mp) {
			return;
		}
		// 如果CD为0，则需要10点气力值释放
		if (readyReleaseSkillData.effortConsume > 0 && this.data.effort < readyReleaseSkillData.effortConsume) {
			return;
		}
		this.data.mp -= readyReleaseSkillData.mpConsume * 100;
		this.hitedTimes = 0;
		this.__currentSkillActionName = skill;
		this.play(this.__currentSkillActionName, true);
		// 如果是必杀技或者辅助技，则消耗所有的强制技能次数
		var currentSkillData = this.roleData.actions.get(skill);
		// 无需CD的技能，都需要减气力值
		if (currentSkillData.effortConsume > 0)
			this.data.effort -= currentSkillData.effortConsume;
		this.cdData.setCD(skill, currentSkillData.cd);
		if (currentSkillData.isAssistSkill() || currentSkillData.isMustSkill()) {
			this.__maxForceSkillTimes = this.data.maxForceSkillTimes;
		}
		// 自动转向支持
		if (enableScaleX)
			if (this.isKeyDown(__keyReceiver.LEFT) || this.isKeyDown(__keyReceiver.RIGHT)) {
				this.scaleX = if (this.isKeyDown(__keyReceiver.LEFT)) -1 else 1;
			}
		if (this.hasEventListener(RoleEvent.SKILL_END)) {
			var event = new RoleEvent(RoleEvent.SKILL_END);
			event.data = skill;
			this.dispatchEvent(event);
		}
	}

	/**
	 * 中断技能释放
	 */
	public function stopSkill():Void {
		this.__currentSkillActionName = null;
		this.__maxForceSkillTimes = 0;
		this.__currentBeStopAction = null;
	}

	/**
	 * 当前技能残影的使用次数，可设置修改当前的残影值
	 */
	public var currentUsedForceSkillTimes(get, set):Int;

	private function set_currentUsedForceSkillTimes(value:Int):Int {
		this.__maxForceSkillTimes = value;
		return value;
	}

	private function get_currentUsedForceSkillTimes():Int {
		return this.__maxForceSkillTimes;
	}

	/**
	 * 当前跳跃的力度
	 */
	private var __jumpForce:Float = 0;

	/**
	 * 已跳跃次数
	 */
	private var __jumpTimes:Int = 0;

	/**
	 * 是否处于快速跳跃状态
	 */
	private var __quickJump = false;

	private var __jumping:Bool = false;

	/**
	 * 是否正在跳跃
	 */
	public var jumping(get, never):Bool;

	private function get_jumping():Bool {
		return this.__jumping;
	}

	/**
	 * 跳跃
	 * @param force 力度比例，默认为`1`
	 */
	public function jump(forceScale:Float = 1):Void {
		jumpByForce(this.data.jump * forceScale);
	}

	/**
	 * 根据力度跳跃
	 * @param force 
	 */
	public function jumpByForce(force:Float):Void {
		__jumpForce = force;
		__jumping = true;
		if (force >= 0)
			__hitMapDisplay = [];
	}

	/**
	 * 跳跃结束时触发
	 */
	public function onJumped():Void {
		if (!isHurt) {
			__jumpTimes = 0;
			__quickJump = false;
		}
		this.airAttackTimes = this.data.maxAirAttackTimes;
		__jumpTestTimes = 0;
		__jumping = false;
		__igonreHitMapDisplay = [];
		if (isHitFly && this.isHurt) {
			// 是否需要反弹
			if (this.__jumpForce < -5) {
				this.jumpByForce(-this.__jumpForce * 0.4);
				//
				var effect = new GameEffect(this, "boom_hit2");
				this.world.addDisplay(effect);
				effect.x = this.x;
				effect.y = this.y;
				effect.blendMode = ADD;
				effect.alpha = 0.5;
				this.world.assets.playSound("blowhit");
			} else {
				// 播放起身动画
				this.playSkill(RoleAction.GET_UP);
				this.__beHitData = null;
				this.isHitFly = false;
				this.hitedTimes = 0;
				this.__jumpTimes = 0;
				this.__quickJump = false;
				this.percentHurtValue = 0;
				//
				var effect = new GameEffect(this, "boom_hit2");
				this.world.addDisplay(effect);
				effect.x = this.x;
				effect.y = this.y;
				effect.blendMode = ADD;
				effect.scaleX = 0.8;
				effect.scaleY = 0.5;
				effect.alpha = 0.5;
				this.world.assets.playSound("blowhit");
			}
		} else {
			// 播放落地动画
			if (this.actionName == RoleAction.JUMP_DOWN) {
				this.playSkill(RoleAction.HIT_MAP);
				this.world.assets.playSound("jumped");
			}
			__jumpForce = 0;
		}
	}

	/**
	 * 克隆该角色
	 */
	public function cloneRole() {
		var clone = new GameRole(this.world, this.assets);
		return clone;
	}

	/**
	 * 残影颜色变换数据
	 */
	public var shadowColorTransform:ColorTransform;

	/**
	 * 创建残影效果
	 * @param color 颜色
	 */
	public function createShadow(?color:ColorTransform):Void {
		#if !editer
		var img = new Image(__movieClip.data);
		img.x = this.x + __movieClip.x * this.scaleX;
		img.y = this.y + __movieClip.y;
		img.scaleX = this.__movieClip.scaleX * this.scaleX;
		img.scaleY = this.__movieClip.scaleY;
		this.world.displayBox.addChildAt(img, 0);
		Actuate.tween(img, 0.5, {alpha: 0}).onComplete(data -> {
			img.parent?.removeChild(img);
		});
		if (color != null)
			img.colorTransform = color;
		else if (shadowColorTransform != null)
			img.colorTransform = shadowColorTransform;
		#end
	}

	/**
	 * 获得角色攻击碰撞块
	 */
	public var currentHitColliderFrameData(get, set):FrameData;

	private function get_currentHitColliderFrameData():FrameData {
		if (__hitCollisionTime <= 0) {
			return null;
		}
		return this.__hitFrameData;
	}

	private function set_currentHitColliderFrameData(value:FrameData):FrameData {
		this.__hitFrameData = value;
		return value;
	}

	/**
	 * 根据圆形范围获得敌人列表
	 * @param len 圆心半径检测范围
	 * @return Array<GameRole>
	 */
	public function getEnemys(?len:Null<Float>):Array<GameRole> {
		var array = [];
		for (role in this.world.roles) {
			if (role.troop != this.troop) {
				if (len == null || Point.distanceByFloat(role.x, role.y, this.x, this.y) < len)
					array.push(role);
			}
		}
		return array;
	}

	/**
	 * 根据矩形获得敌人列表
	 * @param rect 矩形对象
	 * @param autoRoleCenter 是否自动将角色中心设置为矩形中心，设置为`true`后会重新计算矩形的位置
	 * @return Array<GameRole>
	 */
	public function getEnemysByRectangle(rect:Rectangle, autoRoleCenter:Bool = true):Array<GameRole> {
		if (autoRoleCenter) {
			rect.x = this.x - rect.width / 2;
			rect.y = this.y - rect.height / 2;
		}
		var array = [];
		for (role in this.world.roles) {
			if (role.troop != this.troop) {
				if (rect.containsPoint(role.x, role.y))
					array.push(role);
			}
		}
		return array;
	}

	/**
	 * 获得目标敌人
	 * @return Array<GameRole>
	 */
	public function getTargetEnemy():GameRole {
		var array = getEnemys();
		return array[0];
	}

	/**
	 * 检测是否与角色发生碰撞
	 * @param role 
	 * @return Bool
	 */
	public function hitTestRole(role:GameRole):Bool {
		return testCollider(role);
	}

	/**
	 * 跳转到某帧
	 * @param frame 
	 */
	public function goToFrame(frame:Int):Void {
		this.__movieClip.currentFrame = frame;
		this.onPlayChange(null);
	}

	/**
	 * 排斥角色
	 * @param role 
	 */
	public function repelRoles(roles:Array<GameRole>, dt:Float):Void {
		if (this.data.hp == 0)
			return;
		var dtScale = DtTools.mathTimeScale(dt);
		for (role in roles) {
			if (role.isSkilling || role.data.hp == 0) {
				continue;
			}
			var len = Point.distanceByFloat(this.x, this.y, role.x, role.y);
			if (len < 20) {
				var radian = Point.radianByFloat(this.x, this.y, role.x, role.y);
				var lenRate = 1 - len / 20;
				role.body.velocity.x += (Math.cos(radian) * lenRate * 1.5 * dtScale) / GameOption.DT_FPS;
				this.body.velocity.x -= (Math.cos(radian) * lenRate * 1.5 * dtScale) / GameOption.DT_FPS;
			}
		}
	}

	/**
	 * 获得角色，如果角色自身存在，则返回角色自身，否则返回关系role
	 * @return Role
	 */
	public function getRole():GameRole {
		return this;
	}

	/**
	 * 回复血量
	 */
	public function addHp(value:Int):Void {
		this.data.hp += value;
		if (this.data.hp > this.data.maxHp) {
			this.data.hp = this.data.maxHp;
		}
		// 触发回复血量事件
		if (this.hasEventListener(RoleEvent.ADD_HP)) {
			var event = new RoleEvent(RoleEvent.ADD_HP);
			event.data = value;
			this.dispatchEvent(event);
		}
	}

	/**
	 * 增加MP值，请注意值是100点为1颗能量点
	 * @param value 
	 */
	public function addMp(value:Int):Void {
		this.data.mp += value;
		if (this.data.mp > this.data.maxMp) {
			this.data.mp = this.data.maxMp;
		}
	}

	/**
	 * 添加气力值
	 * @param value 
	 */
	public function addEffort(value:Int):Void {
		this.data.effort += value;
		if (this.data.effort > this.data.maxEffort) {
			this.data.effort = this.data.maxEffort;
		}
	}

	/**
	 * 造成伤害
	 * @param enemy 攻击者
	 * @param damage 伤害
	 */
	public function hurt(enemy:IAttackDisplay, damage:HurtData):Void {
		var hurt = new HurtDisplay(damage.value, damage.attackType);
		this.world.worldBox.addChild(hurt);
		hurt.scaleX = hurt.scaleY = 0.25;
		hurt.x = this.x - hurt.width / 2;
		hurt.y = this.y - this.height / 2 - hurt.height / 2;
		Actuate.tween(hurt, 0.5, {alpha: 0, y: hurt.y - 30}).delay(0.5);
		this.data.hp -= damage.value;
		if (this.data.hp <= 0) {
			this.data.hp = 0;
			if (!this.jumping) {
				this.jumpByForce(5);
			}
		}
		// 受伤事件
		if (this.hasEventListener(RoleEvent.HURT)) {
			var event = new RoleEvent(RoleEvent.HURT);
			event.hurtData = damage;
			this.dispatchEvent(event);
		}
		#if !editer
		// 死亡事件
		if (this.data.hp == 0) {
			if (this.isSkilling) {
				this.stopSkill();
			}
			this.isHitFly = true;
			this.dispatchEvent(new RoleEvent(RoleEvent.DEAD, false, true));
		}
		#end
		this.data.addMp(5);
	}

	/**
	 * 通过角色ID更换角色，请注意它只能切换自身的绑定的角色数据，并不包含敌人的角色数据
	 * @param id 
	 */
	public function switchRole(id:String):Void {
		var switchData = this.assets.roleDatas.get(id);
		if (switchData == null)
			throw "SwitchRole data [" + id + "] is null.";
		if (this.__roleData != switchData) {
			this.__roleData = switchData;
			// 构造角色数据
			var currentRate = this.data != null ? this.data.hp / this.data.maxHp : 1;
			var currentRoleData = this.data;
			this.data = new RoleData();
			if (this.world is GameWorld) {
				this.data.applyData(roleData.attrData, cast(this.world, GameWorld).option);
			}
			this.data.hp = Math.round(this.data.maxHp * currentRate);
			// 保留原始的能量值
			if (currentRoleData != null) {
				this.data.effort = currentRoleData.effort;
				this.data.mp = currentRoleData.mp;
			}
			updateAllMovieClipActionData(true);
			this.stopSkill();
			this.play("待机");
			// 由GameWorld控制
			this.updateEnabled = false;
			this.mouseChildren = false;
			// 读取脚本
			script = new RoleScript(this, data.script, assets.strings.get(data.script));
		}
	}

	/**
	 * 根据昵称获得特效显示对象（当前角色或者特效释放的特效），但请注意，自已释放出去的特效中产生的特效，此方法是无法定位的
	 * @param name 
	 * @return DisplayObject
	 */
	public function getGameEffectByName(name:String):GameEffect {
		if (world != null) {
			return world.getGameEffectByName(name, this);
		}
		return null;
	}

	/**
	 * 碰撞检测，可以是特效与角色之间的碰撞，也可以是特效与特效之间的碰撞检测
	 * @param collider 
	 * @return Bool
	 */
	public function testCollider(collider:IAttackDisplay):Bool {
		var hitData = this.currentHitColliderFrameData;
		if (hitData != null) {
			var c = this.getColliders();
			for (shape in c) {
				hitData.testCollision(this, shape);
			}
		}
		return false;
	}

	/**
	 * 获得当前碰撞列表
	 * @return Array<Shape>
	 */
	public function getColliders():Array<Shape> {
		if (this.hitBody.shapes != null) {
			return this.hitBody.shapes;
		}
		return [this.hitBody.shape];
	}

	public function clean():Void {
		this.onClean();
	}

	public function onClean():Void {
		if (this.world != null) {
			this.world.removeDisplay(this);
		}
		this.body = null;
		this.hitBody = null;
		this.world = null;
		if (this.__keyReceiver != null) {
			this.__keyReceiver.dispose();
			this.__keyReceiver = null;
		}
	}
}
